﻿Imports System.Text

Namespace UDPBroadcast

    Public MustInherit Class MessagePackageBase
        Private m_type As MessageType = MessageType.Unknown

        Public Property Type() As MessageType
            Get
                Return Me.m_type
            End Get
            Protected Set(ByVal value As MessageType)
                Me.m_type = value
            End Set
        End Property

        Protected Sub New(ByVal t As MessageType)
            Me.m_type = t
        End Sub

        Public Overridable Function GetPackageData() As Byte()
            Return New Byte() {CByte(Me.Type)}
        End Function

        Public Shared Function GetMessageType(ByVal data As Byte()) As MessageType
            If data Is Nothing OrElse data.Length = 0 Then
                Return MessageType.Unknown
            Else
                Return DirectCast(data(0), MessageType)
            End If
        End Function

    End Class

    Public Class DataMessagePackage(Of T)
        Inherits MessagePackageBase

        Private m_Message As T = Nothing
        Private m_Time As DateTime = Now

        Public Shared Property Charset() As Encoding = Encoding.Unicode

        Public Property Message() As T
            Get
                Return m_Message
            End Get
            Private Set(value As T)
                Me.m_Message = value
            End Set
        End Property

        Public Property Time() As DateTime
            Get
                Return m_Time
            End Get
            Private Set(value As DateTime)
                m_Time = value
            End Set
        End Property

        Public Sub New(ByVal time As DateTime, ByRef obj As T)
            MyBase.New(MessageType.Data)
            Me.Time = time
            Me.Message = obj
        End Sub

        Public Sub New(ByVal data() As Byte)
            MyBase.New(MessageType.Data)
            Try
                If MessagePackageBase.GetMessageType(data) = MessageType.Data Then
                    Dim timeBuffer As Byte() = New Byte(7) {}
                    Array.Copy(data, 1, timeBuffer, 0, 8)
                    Me.Time = DateTime.FromBinary(BitConverter.ToInt64(timeBuffer, 0))
                    Dim strBytes = DataMessagePackage(Of T).Charset.GetString(data, timeBuffer.Length + 1, data.Length - timeBuffer.Length - 1)
                    Me.Message = Deserialize(Of T)(StringToBytes(strBytes))
                Else
                    Throw New ArgumentException("Invalid data bytes for construting a new DataMessagePackage(Of T).")
                End If
            Catch ex As Exception
                Throw ex
            End Try
        End Sub

        Public Overrides Function GetPackageData() As Byte()
            Dim buffer As New List(Of Byte)(100)
            buffer.AddRange(MyBase.GetPackageData())
            buffer.AddRange(BitConverter.GetBytes(Me.Time.ToBinary()))
            buffer.AddRange(DataMessagePackage(Of T).Charset.GetBytes(BytesToString(Serialize(Me.Message))))
            Return buffer.ToArray()
        End Function

        Public Shared Function FromPackage(ByVal data As Byte()) As DataMessagePackage(Of T)
            Try
                If MessagePackageBase.GetMessageType(data) = MessageType.Data Then
                    Dim timeBuffer As Byte() = New Byte(7) {}
                    Array.Copy(data, 1, timeBuffer, 0, 8)
                    Dim time = DateTime.FromBinary(BitConverter.ToInt64(timeBuffer, 0))
                    Dim strBytes = DataMessagePackage(Of T).Charset.GetString(data, timeBuffer.Length + 1, data.Length - timeBuffer.Length - 1)
                    Dim message = Deserialize(Of T)(StringToBytes(strBytes))
                    Return New DataMessagePackage(Of T)(time, message)
                Else
                    Throw New ArgumentException("Invalid data bytes for construting a new DataMessagePackage(Of T).")
                End If
            Catch
                Return Nothing
            End Try
        End Function
    End Class

    Public Class IdentityMessagePackage
        Inherits MessagePackageBase

        Private m_UserName As String = My.User.Name

        Public ReadOnly Property UserName() As String
            Get
                Return Me.m_UserName
            End Get
        End Property

        Public Sub New()
            MyBase.New(MessageType.Identity)
        End Sub

        Public Sub New(ByVal username As String)
            MyBase.New(MessageType.Identity)
            Me.m_UserName = username
        End Sub

        Public Sub New(ByVal buffer() As Byte)
            MyBase.New(MessageType.Identity)
            If MessagePackageBase.GetMessageType(buffer) = MessageType.Identity Then
                Dim strBytes = Encoding.Unicode.GetString(buffer, 1, buffer.Length - 1)
                Me.m_UserName = strBytes
            Else
                Throw New ArgumentException("Invalid data bytes for construting a new IdentityMessagePackage.")
            End If
        End Sub

        Public Overrides Function GetPackageData() As Byte()
            Dim buffer As New List(Of Byte)(100)
            buffer.AddRange(MyBase.GetPackageData())
            buffer.AddRange(Encoding.Unicode.GetBytes(Me.m_UserName))
            Return buffer.ToArray()
        End Function

        Public Shared Function FromPackage(ByVal data As Byte()) As IdentityMessagePackage
            Try
                If MessagePackageBase.GetMessageType(data) = MessageType.Identity Then
                    Dim strBytes = Encoding.Unicode.GetString(data, 1, data.Length - 1)
                    Return New IdentityMessagePackage(strBytes)
                Else
                    Throw New ArgumentException("Invalid data bytes for construting a new IdentityMessagePackage.")
                End If
            Catch
                Return Nothing
            End Try
        End Function

    End Class

    Public Class OnlineMessagePackage
        Inherits MessagePackageBase

        Private m_UserName As String = My.User.Name

        Public ReadOnly Property UserName() As String
            Get
                Return Me.m_UserName
            End Get
        End Property

        Public Sub New()
            MyBase.New(MessageType.Online)
        End Sub

        Public Sub New(ByVal username As String)
            MyBase.New(MessageType.Online)
            Me.m_UserName = username
        End Sub

        Public Sub New(ByVal buffer() As Byte)
            MyBase.New(MessageType.Online)
            If MessagePackageBase.GetMessageType(buffer) = MessageType.Online Then
                Dim strBytes = Encoding.Unicode.GetString(buffer, 1, buffer.Length - 1)
                Me.m_UserName = strBytes
            Else
                Throw New ArgumentException("Invalid data bytes for construting a new OnlineMessagePackage.")
            End If
        End Sub

        Public Overrides Function GetPackageData() As Byte()
            Dim buffer As New List(Of Byte)(100)
            buffer.AddRange(MyBase.GetPackageData())
            buffer.AddRange(Encoding.Unicode.GetBytes(Me.m_UserName))
            Return buffer.ToArray()
        End Function

        Public Shared Function FromPackage(ByVal data As Byte()) As IdentityMessagePackage
            Try
                If MessagePackageBase.GetMessageType(data) = MessageType.Online Then
                    Dim strBytes = Encoding.Unicode.GetString(data, 1, data.Length - 1)
                    Return New IdentityMessagePackage(strBytes)
                Else
                    Throw New ArgumentException("Invalid data bytes for construting a new OnlineMessagePackage.")
                End If
            Catch
                Return Nothing
            End Try
        End Function

    End Class

    Public Class OfflineMessagePackage
        Inherits MessagePackageBase

        Public Sub New()
            MyBase.New(MessageType.Offline)
        End Sub

    End Class


    Public Class QueryMessagePackage
        Inherits MessagePackageBase

        Public Sub New()
            MyBase.New(MessageType.Query)
        End Sub

    End Class

End Namespace